package upload

import (
	"encoding/xml"
	"errors"
	"fmt"
	"hft/global"
	"mime/multipart"
	"os"
	"strings"
	"time"

	"hft/Http/Models/response"

	"github.com/aliyun/aliyun-oss-go-sdk/oss"
)

type AliyunOSS struct{}

func (*AliyunOSS) UploadFile(file *multipart.FileHeader, ossFilename string) (string, string, error) {
	bucket, err := NewBucket()
	if err != nil {
		return "", "", errors.New("function AliyunOSS.NewBucket() Failed, err:" + err.Error())
	}

	// 读取本地文件。
	f, openError := file.Open()
	if openError != nil {
		return "", "", errors.New("function file.Open() Failed, err:" + openError.Error())
	}
	defer f.Close() // 创建文件 defer 关闭
	// 上传阿里云路径 文件名格式 自己可以改 建议保证唯一性
	// yunFileTmpPath := filepath.Join("uploads", time.Now().Format("2006-01-02")) + "/" + file.Filename
	var nowDir = strings.Join(strings.Split(time.Now().Format("2006-01-02"), "-"), "")
	yunFileTmpPath := global.OC_CONFIG.AliyunOSS.BasePath + "/" + nowDir + "/" + ossFilename

	// 上传文件流。
	err = bucket.PutObject(yunFileTmpPath, f)
	if err != nil {
		return "", "", errors.New("function formUploader.Put() Failed, err:" + err.Error())
	}

	return global.OC_CONFIG.AliyunOSS.BucketUrl + "/" + yunFileTmpPath, "/" + yunFileTmpPath, nil
}

func (*AliyunOSS) DeleteFile(keys []string) error {
	bucket, err := NewBucket()
	if err != nil {
		return errors.New("function AliyunOSS.NewBucket() Failed, err:" + err.Error())
	}
	// var newKeys []string

	// for _, v := range keys {
	// 	path := v[1:len(v)]
	// 	newKeys = append(newKeys, path)
	// }
	_, err = bucket.DeleteObjects(keys)

	if err != nil {
		fmt.Println(err)
		return errors.New("function AliyunOSS.DeleteObjects() Failed, err:" + err.Error())
	}

	return nil
}

func NewBucket() (*oss.Bucket, error) {
	client, err := oss.New(global.OC_CONFIG.AliyunOSS.Endpoint, global.OC_CONFIG.AliyunOSS.AccessKeyId, global.OC_CONFIG.AliyunOSS.AccessKeySecret)

	if err != nil {
		return nil, err
	}

	// 获取存储空间。
	bucket, err := client.Bucket(global.OC_CONFIG.AliyunOSS.BucketName)
	if err != nil {
		return nil, err
	}

	return bucket, nil
}

func (*AliyunOSS) UploadMultiFile(fileMD5 string, fileName string, index int, chunkTotal int, file multipart.File, size int64) (data *response.FileRes, err error) {

	var bucket, _ = NewBucket()
	list, err := global.OC_REDIS.LRange(fileMD5+"_index", 0, -1).Result() //获取当前文件的list，看看是否上传过

	if err != nil {
		fmt.Println(err.Error())
		return nil, err
	}

	var nowDir = strings.Join(strings.Split(time.Now().Format("2006-01-02"), "-"), "")

	var uploadFilename = fmt.Sprintf("%s/%s/%s", global.OC_CONFIG.AliyunOSS.BasePath, nowDir, fileName)

	if err != nil {
		return nil, errors.New(err.Error())
	}

	if len(list) != index {
		global.OC_REDIS.LTrim(fileMD5+"_index", -1, -1)
		global.OC_REDIS.Expire(fileMD5+"_index", 24*time.Hour) //保留24小时
	} // 如果list的长度和文件的传输索引不一致，就清除之前list重传
	_, err = global.OC_REDIS.Get(fileMD5).Result() //获取这个文件的md5缓存 如果没有md5就创建该文件的上传记录
	if err != nil {
		imur, err := bucket.InitiateMultipartUpload(uploadFilename, oss.ObjectStorageClass(oss.StorageStandard))
		if err != nil {
			fmt.Println(err.Error(), imur)
			os.Exit(-1)
		}
		global.OC_REDIS.Set(fileMD5, imur.UploadID, 24*time.Hour)
	}

	val, _ := global.OC_REDIS.Get(fileMD5).Result() //获取文件的md5记录

	// 创建新的上传oss切片
	newImur := &oss.InitiateMultipartUploadResult{XMLName: xml.Name{Space: "", Local: ""}, Key: uploadFilename, UploadID: val, Bucket: bucket.BucketName}
	// 分片
	slicePart, err := bucket.UploadPart(*newImur, file, size, index+1)

	if err != nil {
		fmt.Print(err)
		return nil, errors.New("文件传输错误")
	}

	err = global.OC_REDIS.RPush(fileMD5+"_index", slicePart.ETag).Err()

	fmt.Println(slicePart.ETag, "列表", list, index+1, "-----------", len(list))

	if err != nil {
		fmt.Println("错误", err)
		return nil, errors.New("获取文件分片失败")
	}
	if chunkTotal == index+1 { //最后一片
		var parts []oss.UploadPart
		for k, v := range list {
			var part = &oss.UploadPart{XMLName: xml.Name{Space: "", Local: ""}, PartNumber: k + 1, ETag: v}
			parts = append(parts, *part)
		}

		parts = append(parts, slicePart)

		objactAcl := oss.ObjectACL(oss.ACLPrivate)                           //继承bucket的权限
		_, err := bucket.CompleteMultipartUpload(*newImur, parts, objactAcl) //合并
		if err != nil {
			fmt.Println(err.Error())
			return nil, errors.New("文件合并失败，请重新上传")
		}
		global.OC_REDIS.Del(fileMD5, fileMD5+"_index") //删掉记录

		// 构建文件记录

	}

	data = &response.FileRes{ChunkTotal: chunkTotal, Index: index + 1, FileName: fileName, FilePath: global.OC_CONFIG.AliyunOSS.BucketUrl + "/" + uploadFilename, ObjectName: "/" + uploadFilename}

	return data, nil
}

var OssAliyun = new(AliyunOSS)
